#ifndef __HELP_HPP__
#define __HELP_HPP__

#include <iostream>
#include <string>
#include <sqlite3.h>
#include <string>
#include <vector>
#include <iomanip>
#include <sstream>
#include <random>
#include <atomic>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <fstream>
#include "mq_log.hpp"
#include <stdlib.h>
#include <cstring>

namespace mq
{
    namespace Helper
    {
        class SqliteHelper
        {
        public:
            // 回调函数指针。
            typedef int(*SqliteCallback)(void*,int,char**,char**);
            SqliteHelper(const std::string& dbfile)
                :_dbfile(dbfile)
                ,_handler(nullptr)
            {}
            ~SqliteHelper()
            {
                close();
            }
            bool open(int safe_leve = SQLITE_OPEN_FULLMUTEX)
            {
                int ret = sqlite3_open_v2(_dbfile.c_str(),&_handler
                ,SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | safe_leve,nullptr);
                if(ret != SQLITE_OK)
                {
                    std::cout << "创建/打开数据库失败:";
                    std::cout << sqlite3_errmsg(_handler) << std::endl;
                    return false;
                }
                return true;
            }
            bool exec(const std::string& sql,SqliteCallback cb,void* arg)
            {
                int ret = sqlite3_exec(_handler,sql.c_str(),cb,arg,nullptr);
                if(ret != SQLITE_OK)
                {
                    std::cout << sql << std::endl;
                    std::cout << "执行语句失败:";
                    std::cout << sqlite3_errmsg(_handler) << std::endl;
                    return false;
                }

                DLOG("执行语句成功");
                
                return true;
            }
            void close()
            {
                if(_handler)
                {
                    sqlite3_close_v2(_handler);
                }
            }
        private:
            std::string _dbfile;
            sqlite3* _handler;
        };

        class StrHelper
        {
        public:
            static size_t split(const std::string& str,const std::string& sep,std::vector<std::string>& result)
            {
                size_t pos = 0 , idx = 0;
                while(idx < str.size())
                {
                    pos = str.find(sep,idx);
                    if(pos == std::string::npos)
                    {
                        result.emplace_back(str.substr(idx));
                        break;
                    }
                    if(pos == idx)
                    {
                        ++idx;
                        continue;
                    }
                    result.emplace_back(str.substr(idx,pos - idx));
                    idx = pos + 1;
                }
                return result.size();
            }
        };

        class UuidHelper
        {
        public:
            static std::string uuid()
            {
                std::random_device rd;
                // std::cout << rd() << std::endl;
                // 给梅森特算法一个种子。
                std::mt19937_64 generator(rd());
                // 给它种一个种子。
                std::uniform_int_distribution<int> distribution(0,255);
                // std::cout << std::setw(2) << std::setfill('0') << std::hex <<  distribution(generator) << std::endl;
                std::stringstream ss;
                for(int i = 0;i < 8;++i)
                {
                    // std::cout << std::setw(2) << std::setfill('0') << std::hex << distribution(generator) << std::endl;
                    ss << std::setw(2) << std::setfill('0') << std::hex <<  distribution(generator);
                    if(i == 3 || i == 5 || i == 7)
                    {
                        ss << "-";
                    }
                } 
                // 用一个静态变量来计数uuid生成的数量。
                static std::atomic<size_t> count(1);
                size_t num = count.fetch_add(1);
                for(int i = 7;i >= 0;--i)
                {
                    // 向右移动一个字节。
                    ss << std::setw(2) << std::setfill('0') << std::hex << ((num >> (i * 8)) & 0xff);
                    if(i == 6)
                    {
                        // 844模式。
                        ss << "-";
                    }
                }
                // static std::atomic<int> count(1);
                // int num = count.fetch_add(1);
                // for(int i = 7;i >= 0;--i)
                // {
                //     // 向右移动一个字节。
                //     // 4 * 8 = 32，int，所以不移动。
                //     ss << std::setw(2) << std::setfill('0') << std::hex << ((num >> (i * 8)) & 0xff);
                //     if((num >> (i * 8)) == 1)
                //     {
                //         std::cout << i << std::endl;
                //     }
                //     if(i == 6)
                //     {
                //         // 844模式。
                //         ss << "-";
                //     }
                // }
                return ss.str();
            }
        private:
            ;
        };
        class FileHelper
        {
        public:
            FileHelper(std::string filename)
                :_filename(filename)
            {}
            bool exist()
            {
                struct stat st;
                return (stat(_filename.c_str(),&st) == 0);
            }
            size_t size()
            {
                struct stat st;
                stat(_filename.c_str(),&st);
                return st.st_size;
            }
            bool read(char* str,size_t offset,size_t len)
            {
                if(exist() == false)
                {
                    ELOG("文件不存在");
                    return false;
                }
                std::ifstream ifs(_filename,std::ios::binary | std::ios::in);
                if(ifs.good() == false)
                {
                    ELOG("文件读取失败");
                    ifs.close();
                    return false;
                }
                ifs.seekg(offset,std::ios::beg);
                ifs.read(str,len);

                return true;
            }
            bool read(std::string& str)
            {
                // 取出地址String的字符串地址。
                // str,没有空间，这属于非法操作。
                // 应先调整str的大小。
                str.resize(size());
                return read(&str[0],0,size());
            }
            bool write(const char* str,size_t offset,size_t len)
            {
                if(exist() == false)
                {
                    ELOG("文件不存在");
                    return false;
                }
                // 用ofs不能有效的根据偏移量定位好要输出的文件位置。
                std::fstream fs(_filename,std::ios::binary | std::ios::in | std::ios::out);
                if(fs.good() == false)
                {
                    ELOG("文件写入失败");
                    fs.close();
                    return false;
                }
                fs.seekp(offset,std::ios::beg);
                fs.write(str,len);
                fs.close();

                return true;
            }
            bool write(const std::string str)
            {
                // 容易乱码。(覆盖之前的数据)
                // 还是先删除再写入的好。
                return write(str.c_str(),0,str.size());
            }
            // 关于文件管理的都打上static函数。可以在类域外用类域::调用。
            static bool rename(const std::string& old_filename,const std::string& new_filename)
            {
                // ::代表全局下的函数或是变量。
                return ::rename(old_filename.c_str(),new_filename.c_str());
            }
            bool rename(const std::string& new_filename)
            {
                // ::代表全局下的函数或是变量。
                return ::rename(_filename.c_str(),new_filename.c_str());
            }
            static bool createFile(const std::string& filename)
            {
                std::ofstream ofs(filename,std::ios::binary | std::ios::out);
                if(ofs.is_open() == false && errno != EEXIST)
                {
                    ELOG("文件创建失败:%s",::strerror(errno));
                    return false;
                }

                return true;
            }
            static bool removeFile(const std::string& filename)
            {
                return (::remove(filename.c_str()) == 0);
            }
            static std::string parentDirctory(const std::string parent)
            {
                size_t pos = parent.find_last_of("/\\");
                return parent.substr(0,pos + 1);
            }
            static bool createDirectory(const std::string& pathname)
            {
                size_t pos = 0,idx = 0;
                while(idx < pathname.size())
                {
                    pos = pathname.find_first_of("/\\",idx);
                    if(pos == std::string::npos)
                    {
                        return (mkdir((pathname.c_str()),0775) == 0);
                    }
                    std::string name = pathname.substr(0,pos);
                    int ret = mkdir(name.c_str(),0775);
                    if(ret != 0 && errno != EEXIST)
                    {
                        ELOG("创建目录失败:%s",strerror(errno));
                        return false;
                    }
                    idx = pos + 1;
                }
                return true;
            }
            static bool removeDirectory(const std::string& pathname)
            {
                // 记得空行。
                std::string command = "rm -fr " + pathname;
                return (::system(command.c_str()) != -1);
            }
        private:
            std::string _filename;
        };
    }
}
#endif